﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;
using System.IO;
using System.Windows.Media.Imaging;
using System.Threading;
using Kiva7.Utilities;

namespace Kiva7.DataRequests
{
    public class DataCache
    {
        private const string CacheFileName = "CacheFile.xml";
        private const string StringDirectory = "StringCache";

        private static DataCache _current;
        private readonly DataCacheItemDictionary _cache = new DataCacheItemDictionary();

        public DataCache()
        {
            LoadCacheItems();
        }

        public static DataCache Current
        {
            get
            {
                if (_current == null)
                {
                    _current = new DataCache();
                }
                return _current;
            }
        }

        private static bool ShouldRefreshItem(DataCacheItem item)
        {
            if ((DateTime.Now - item.Created).Days > 30)
            {
                return true;
            }
            return false;
        }

        public string RetrieveString(Uri uri)
        {
            IsolatedStorageFileStream s = null;
            try
            {
                
                if (_cache.ContainsKey(uri))
                {
                    DataCacheItem item = _cache[uri];
                    if (ShouldRefreshItem(item))
                    {
                        return null;
                    }
                    // todo check created date here.
                    item.LastUsed = DateTime.Now;
                    IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
                    string path = System.IO.Path.Combine(StringDirectory, item.FileName);
                    if (file.FileExists(path))
                    {
                        s = file.OpenFile(path, FileMode.Open);
                        StreamReader sr = new StreamReader(s);
                        return sr.ReadToEnd();
                    }
                    else
                    {
                        return null;
                    }
                }
            }
            catch
            {
            }
            finally
            {
                if (s != null)
                {
                    s.Close();
                }
            }
            return null;
        }

        public void StoreString(Uri uri, string data)
        {
            if (data == null)
                return;
            DataCacheItem item;
            
            if (_cache.ContainsKey(uri))
            {
                item = _cache[uri];
            }
            else
            {
                item = new DataCacheItem(uri.ToString(), data.Length);
            }

            IsolatedStorageFileStream s = null;
            StreamWriter sw = null;
            try
            {
                IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();

                if (!file.DirectoryExists(StringDirectory))
                {
                    file.CreateDirectory(StringDirectory);
                }

                s = file.CreateFile(System.IO.Path.Combine(StringDirectory, item.FileName));
                sw = new StreamWriter(s);
                sw.Write(data);

                if (!_cache.ContainsKey(uri))
                {
                    _cache.Add(uri, item);
                }
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandleException(ex);
            }
            finally
            {
                if (sw != null)
                {
                    sw.Close();
                }
                if (s != null)
                {
                    s.Close();
                }
            }
        }

        public class T
        {
            public DataCacheItem Item;
            public AutoResetEvent Event;
            public BitmapImage Image;
            public Uri Uri;
        }

        public void Clear()
        {
            _cache.Clear();
            DeleteFiles(StringDirectory);
        }

        private static void DeleteFiles(string path)
        {
            IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
            string[] fileNames = file.GetFileNames();
            foreach (string fileName in fileNames)
            {
                file.DeleteFile(fileName);
            }
        }

        private void LoadCacheItems()
        {
            IsolatedStorageFileStream s = null;
            try
            {
                IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
                if (file.FileExists(CacheFileName))
                {
                    s = file.OpenFile(CacheFileName, FileMode.Open, FileAccess.Read);
                    XmlSerializer xs = new XmlSerializer(typeof(DataCacheFile));
                    DataCacheFile cacheFile = xs.Deserialize(s) as DataCacheFile;
                    if (cacheFile != null)
                    {
                        foreach (DataCacheItem item in cacheFile.Items)
                        {
                            _cache.Add(new Uri(item.SourceUri), item);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandleException(ex);
            }
            finally
            {
                if (s != null)
                {
                    s.Close();
                }
            }
        }

        public void StoreCacheItems()
        {
            IsolatedStorageFileStream s = null;
            try
            {
                IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
                s = file.CreateFile(CacheFileName);
                XmlSerializer xs = new XmlSerializer(typeof(DataCacheFile));
                DataCacheItemList list = new DataCacheItemList();
                list.AddRange(_cache.Select(item => item.Value));
                DataCacheFile cacheFile = new DataCacheFile(list);
                xs.Serialize(s, cacheFile);
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandleException(ex);
            }
            finally
            {
                if (s != null)
                {
                    s.Close();
                }
            }
        }

        private void DeleteCacheItems()
        {
            // todo
        }
    }

    public class DataCacheItem
    {
        public DataCacheItem()
        {
        }

        public DataCacheItem(string sourceUri, int size)
        {
            SourceUri = sourceUri;
            Size = size;
            Created = DateTime.Now;
            LastUsed = DateTime.Now;
            FileName = Guid.NewGuid() + ".xmls";
        }

        public DateTime Created { get; set; }
        public DateTime LastUsed { get; set; }
        public string SourceUri { get; set; }
        public string FileName { get; set; }
        public int Size { get; set; }
    }

    public class DataCacheItemList : List<DataCacheItem>
    {
    }

    public class DataCacheItemDictionary : Dictionary<Uri, DataCacheItem>
    {
    }


    public class DataCacheFile
    {
        public DataCacheFile()
        {
        }

        public DataCacheFile(DataCacheItemList items)
        {
            _items = items;
        }

        private readonly DataCacheItemList _items = new DataCacheItemList();
        public DataCacheItemList Items
        {
            get
            {
                return _items;
            }
        }
    }
}
